package com.han.yrpc.registrycenter.localcache;

import com.han.yrpc.core.registry.ServiceInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@Component
public class DefaultRegistryInitializer implements RegistryInitializer {

    public static final int PORT = 10001;

    private boolean starter = false;

    private static final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    private final ServiceRegistryHandle serviceRegistryHandle;
    private final ServiceDiscoverHandle serviceDiscoverHandle;

    public DefaultRegistryInitializer(ServiceRegistryHandle serviceRegistryHandle, ServiceDiscoverHandle serviceDiscoverHandle) {
        this.serviceRegistryHandle = serviceRegistryHandle;
        this.serviceDiscoverHandle = serviceDiscoverHandle;
    }

    public void initialize() {
        new Thread(() -> {
            if (starter) {
                return;
            }
            log.info("initialize default registry center");
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket();
                serverSocket.bind(new InetSocketAddress(PORT));
                starter = true;
                while (true) {
                    Socket socket = serverSocket.accept();
                    executorService.execute(() -> this.serverTask(socket));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

    }

    private void serverTask(Socket socket) {

        try (ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
             ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());) {
            boolean registry = inputStream.readBoolean();
            String serviceName = inputStream.readUTF();
            if (registry) {
//                log.info("[{}] register ....", serviceName);

                String host = inputStream.readUTF();
                int port = inputStream.readInt();
                serviceRegistryHandle.registry(serviceName, new ServiceInfo(host, port));
                outputStream.writeBoolean(true);
//                log.info("[{}] register success", serviceName);
            } else {
//                log.info("[{}] discover .....", serviceName);
                Set<ServiceInfo> serviceSet = serviceDiscoverHandle.discover(serviceName);
                outputStream.writeObject(serviceSet);
            }
            outputStream.flush();
        } catch (IOException e) {
            log.error("occur Exception: ", e);
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
